type TargetContext = '_self' | '_parent' | '_blank' | '_top';

export const openWindow = (
  url: string,
  opts?: { target?: TargetContext; [key: string]: any }
) => {
  const { target = '_blank', ...others } = opts || {};
  window.open(
    url,
    target,
    Object.entries(others)
      .reduce((preValue: string[], curValue) => {
        const [key, value] = curValue;
        return [...preValue, `${key}=${value}`];
      }, [])
      .join(',')
  );
};

export const regexUrl = new RegExp(
  '^(?!mailto:)(?:(?:http|https|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$',
  'i'
);

/**
 * 文件下载
 */
export function downloadFile(src: string) {
  if (import.meta.env.VITE_API_BASE_URL) {
    const baseURL = import.meta.env.VITE_API_BASE_URL;
    window.open(`${baseURL}/adminapi/common/download?file=${src}`, '_blank');
  }
}

/**
 * 树状结构添加disabled
 */
export function disabledTree(tree: any, id: number, parentId = 0, disabledData: any = []) {
  tree.forEach(function (item: any, index: number) {
    if (item.id === id) {
      // 顶级
      item.disabled = true;
      disabledData[item.id] = true;
    } else if (item.parent_id === id && id !== parentId) {
      // 非顶级
      item.disabled = true;
      disabledData[item.parent_id] = true;
    } else if (item.parent_id !== 0 && item.parent_id === parentId && disabledData[item.parent_id]) {
      // 子集
      item.disabled = true;
      disabledData[item.id] = true;
    } else {
      //
    }
    if (item.children) {
      disabledTree(item.children, id, item.id, disabledData);
    }
  });
  return tree;
}

/**
 * 树状结构转为一维数组
 */
export function treeToList(tree: any, children = 'children') {
  let list = <any>[];
  tree.forEach((item: any) => {
    list.push(item);
    if (item[children] && item[children].length > 0) {
      // list = [...list, ...treeToList(item[children])];
      list = [...list, ...item[children]];
    }
  });
  return list;
}

/**
 * 获取文件类型
 */
export function getFileType(src: string) {
  if (src) {
    const point = src.lastIndexOf('.');
    return src.substr(point + 1);
  }
  return '';
}

/**
 * 计算两个日期之间的差值
 */
export function getDiffDay(beginDate: string, endDate: string) {
  // 将两个日期都转换为毫秒格式，然后做差
  const beginTime = Date.parse(beginDate);
  const endTime = Date.parse(endDate);
  if (endTime > beginTime) {
    const diffDate = Math.abs(endTime - beginTime); // 取相差毫秒数的绝对值
    // return Math.floor(diffDate / (1000 * 3600 * 24)); // 向下取整
    return Math.ceil(diffDate / (1000 * 3600 * 24)); // 向上取整
  }
  return 0;
}

/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string | null}
 */
export function parseTime(time: any, cFormat: string) {
  if (arguments.length === 0 || !time) {
    return null;
  }
  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}';
  let date;
  if (typeof time === 'object') {
    date = time;
  } else {
    if ((typeof time === 'string')) {
      if ((/^[0-9]+$/.test(time))) {
        // support "1548221490638"
        time = parseInt(time, 10);
      } else {
        // support safari
        // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
        time = time.replace(new RegExp(/-/gm), '/');
      }
    }
    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = Number(time) * 1000;
    }
    date = new Date(time);
  }
  const formatObj = <any>{
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  };
  return format.replace(/{([ymdhisa])+}/g, (result, key) => {
    const value = formatObj[key];
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') {
      return ['日', '一', '二', '三', '四', '五', '六'][value];
    }
    return value.toString().padStart(2, '0');
  });
}

/**
 * 友好时间
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time: any, option: string) {
  if (time.length === 10) {
    time = parseInt(time, 10) * 1000;
  } else {
    time = +time;
  }
  const d: any = new Date(time);
  const now = Date.now();

  const diff = (now - d) / 1000;
  let result: any = '';
  if (diff < 30) {
    result = '刚刚';
  } else if (diff < 3600) {
    // less 1 hour
    result = `${Math.ceil(diff / 60)}分钟前`;
  } else if (diff < 3600 * 24) {
    result = `${Math.ceil(diff / 3600)}小时前`;
  } else if (diff < 3600 * 24 * 2) {
    result = '1天前';
  } else if (option) {
    result = parseTime(time, option);
  } else {
    result = `${d.getMonth() + 1}月${d.getDate()}日${d.getHours()}时${d.getMinutes()}分`;
  }
  return result;
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url: string) {
  url = url == null ? window.location.href : url;
  const search = url.substring(url.lastIndexOf('?') + 1);
  const obj = <any>{};
  const reg = /([^?&=]+)=([^?&=]*)/g;
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1);
    let val = decodeURIComponent($2);
    val = String(val);
    obj[name] = val;
    return rs;
  });
  return obj;
}

/**
 * 字节长度
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str: string) {
  // returns the byte length of an utf8 string
  let s = str.length;
  for (let i = str.length - 1; i >= 0; i-=1) {
    const code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) {
      s += 1;
    } else if (code > 0x7ff && code <= 0xffff) {
      s += 2;
    } else if (code >= 0xDC00 && code <= 0xDFFF) {
      i -= 1;
    }
  }
  return s;
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual: string[]) {
  const newArray = [];
  for (let i = 0; i < actual.length; i+=1) {
    if (actual[i]) {
      newArray.push(actual[i]);
    }
  }
  return newArray;
}

/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json: any) {
  if (!json) {
    return '';
  }
  return cleanArray(
    Object.keys(json).map(key => {
      if (json[key] === undefined) {
        return '';
      }
      return `${encodeURIComponent(key)}=${encodeURIComponent(json[key])}`;
    })
  ).join('&');
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url: string) {
  const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ');
  if (!search) {
    return {};
  }
  const obj = <any>{};
  const searchArr = search.split('&');
  searchArr.forEach(v => {
    const index = v.indexOf('=');
    if (index !== -1) {
      const name = v.substring(0, index);
      const val = v.substring(index + 1, v.length);
      obj[name] = val;
    }
  });
  return obj;
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val: string) {
  const div = document.createElement('div');
  div.innerHTML = val;
  return div.textContent || div.innerText;
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target: any, source: any) {
  if (typeof target !== 'object') {
    target = {};
  }
  if (Array.isArray(source)) {
    return source.slice();
  }
  Object.keys(source).forEach(property => {
    const sourceProperty = source[property];
    if (typeof sourceProperty === 'object') {
      target[property] = objectMerge(target[property], sourceProperty);
    } else {
      target[property] = sourceProperty;
    }
  })
  return target;
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element: any, className: string) {
  if (!element || !className) {
    return;
  }
  let classString = element.className;
  const nameIndex = classString.indexOf(className);
  if (nameIndex === -1) {
    classString += className;
  } else {
    classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length);
  }
  element.className = classString;
}

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type: string) {
  if (type === 'start') {
    return new Date().getTime() - 3600 * 1000 * 24 * 90;
  }
  return new Date(new Date().toDateString());
}

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr: string[]) {
  return Array.from(new Set(arr));
}

/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele: any, cls: string) {
  return !!ele.className.match(new RegExp(`(\\s|^)${cls}(\\s|$)`));
}

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele: any, cls: string) {
  if (!hasClass(ele, cls)) {
    ele.className += ` ${cls}`;
  }
}

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele: any, cls: string) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp(`(\\s|^)${cls}(\\s|$)`);
    ele.className = ele.className.replace(reg, ' ');
  }
}

export default null;
